package cn.jingyuan.bee.utils.io.resource;

import cn.jingyuan.bee.utils.CharsetUtils;
import cn.jingyuan.bee.utils.ClassLoaderUtils;
import cn.jingyuan.bee.utils.StringUtils;
import cn.jingyuan.bee.utils.URLUtils;
import cn.jingyuan.bee.utils.collection.CollectionUtils;
import cn.jingyuan.bee.utils.collection.EnumerationIter;
import cn.jingyuan.bee.utils.io.FileUtils;
import cn.jingyuan.bee.utils.io.IORuntimeException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.List;

/**
 * ClassPath 资源工具类
 */
public class ResourceUtils {

    /**
     * 读取 Classpath 下的资源为字符串，使用 UTF-8 编码
     *
     * @param resource 资源路径，使用相对 ClassPath 的路径
     *
     * @return 资源内容
     */
    public static String readUtf8String(String resource) {
        return readString(resource, CharsetUtils.CHARSET_UTF_8);
    }

    /**
     * 读取 Classpath 下的资源为字符串
     *
     * @param resource 可以是绝对路径，也可以是相对路径（相对 ClassPath）
     * @param charset 编码
     *
     * @return 资源内容
     */
    public static String readString(String resource, Charset charset) {
        return getResourceObj(resource).readString(charset);
    }

    /**
     * 读取 Classpath 下的资源为 byte[]
     *
     * @param resource 可以是绝对路径，也可以是相对路径（相对 ClassPath）
     *
     * @return 资源内容
     */
    public static byte[] readBytes(String resource) {
        return getResourceObj(resource).readBytes();
    }

    /**
     * 从 ClassPath 资源中获取 {@link InputStream}
     *
     * @param resurce ClassPath 资源
     *
     * @return {@link InputStream}
     *
     * @throws NoResourceException 资源不存在异常
     */
    public static InputStream getStream(String resurce) throws NoResourceException {
        return getResourceObj(resurce).getStream();
    }

    /**
     * 从 ClassPath 资源中获取 {@link InputStream}，当资源不存在时返回 null
     *
     * @param resurce ClassPath 资源
     *
     * @return {@link InputStream}
     */
    public static InputStream getStreamSafe(String resurce) {
        try {
            return getResourceObj(resurce).getStream();
        } catch (NoResourceException e) {
            // ignore
        }
        return null;
    }

    /**
     * 从 ClassPath 资源中获取 {@link BufferedReader}
     *
     * @param resurce ClassPath 资源
     * @param charset 编码
     *
     * @return {@link InputStream}
     */
    public static BufferedReader getReader(String resurce, Charset charset) {
        return getResourceObj(resurce).getReader(charset);
    }

    /**
     * 获得资源的 URL<br>
     * 路径用/分隔，例如:
     *
     * <pre>
     * config/a/db.config
     * spring/xml/test.xml
     * </pre>
     *
     * @param resource 资源（相对 Classpath 的路径）
     *
     * @return 资源 URL
     */
    public static URL getResource(String resource) throws IORuntimeException {
        return getResource(resource, null);
    }

    /**
     * 获取指定路径下的资源列表<br>
     * 路径格式必须为目录格式,用/分隔，例如:
     *
     * <pre>
     * config/a
     * spring/xml
     * </pre>
     *
     * @param resource 资源路径
     *
     * @return 资源列表
     */
    public static List<URL> getResources(String resource) {
        final Enumeration<URL> resources;
        try {
            resources = ClassLoaderUtils.getClassLoader().getResources(resource);
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
        return CollectionUtils.newArrayList(resources);
    }

    /**
     * 获取指定路径下的资源 Iterator<br>
     * 路径格式必须为目录格式,用/分隔，例如:
     *
     * <pre>
     * config/a
     * spring/xml
     * </pre>
     *
     * @param resource 资源路径
     *
     * @return 资源列表
     */
    public static EnumerationIter<URL> getResourceIter(String resource) {
        final Enumeration<URL> resources;
        try {
            resources = ClassLoaderUtils.getClassLoader().getResources(resource);
        } catch (IOException e) {
            throw new IORuntimeException(e);
        }
        return new EnumerationIter<>(resources);
    }

    /**
     * 获得资源相对路径对应的 URL
     *
     * @param resource 资源相对路径
     * @param baseClass 基准 Class，获得的相对路径相对于此 Class 所在路径，如果为 {@code null} 则相对 ClassPath
     *
     * @return {@link URL}
     */
    public static URL getResource(String resource, Class<?> baseClass) {
        return (null != baseClass) ? baseClass.getResource(resource) : ClassLoaderUtils.getClassLoader().getResource(resource);
    }

    /**
     * 获取 {@link Resource} 资源对象<br>
     * 如果提供路径为绝对路径或路径以 file:开头，返回 {@link FileResource}，否则返回 {@link ClassPathResource}
     *
     * @param path 路径，可以是绝对路径，也可以是相对路径（相对 ClassPath）
     *
     * @return {@link Resource} 资源对象
     */
    public static Resource getResourceObj(String path) {
        if (StringUtils.isNotBlank(path)) {
            if (path.startsWith(URLUtils.FILE_URL_PREFIX) || FileUtils.isAbsolutePath(path)) {
                return new FileResource(path);
            }
        }
        return new ClassPathResource(path);
    }

}
